package gl.java.umsp.match;

import gl.java.umsp.ErrCode;
import gl.java.umsp.UmspConfig;
import gl.java.umsp.bean.Match;
import gl.java.umsp.bean.MatchResult;
import gl.java.umsp.bean.Room;
import gl.java.umsp.event.Event;
import gl.java.umsp.event.EventSubscriber;
import gl.java.umsp.event.IEventSubscriber;
import gl.java.umsp.room.RoomServiceConfig;
import gl.java.util.PropertiesUtil;
import gl.java.util.ThreadUtil;
import io.netty.util.concurrent.SingleThreadEventExecutor;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;

/**
 * 匹配服务,必须是单线程设计才能保证数据的原子性,否则需要用到redis的分布式锁.</br>
 * start->init db -> match -> stop -> close db connect;</br>
 * 初始话数据源,当前版本使用redis作为数据源
 *
 * @author geliang
 * @time 2017-09-13 02:05
 */
@Slf4j
public class MatchService implements IMatch {
    static {
        PropertiesUtil.loadAndSave("config.properties");
    }

    private static final String KEY_MATCH_SERVICE_LIST = "MatchServiceList";
    private MatchServiceConfig serviceConfig = MatchServiceConfig.getDefaultConfig();


    private MatchService() {

    }

    private MatchHandler handler = new MatchHandler();

    private static MatchService INSTANCE = new MatchService();

    /**
     * 启动服务
     */
    public void start(MatchServiceConfig config) {
        if (config != null) {
            this.serviceConfig = config;
        }

        try {
            for (IMatch iMatch : MatchServiceConfig.SupportMatchTypeList) {
                log.info("MatchServiceConfig -> Support Match Type:" + MatchType.toString(iMatch.getMatchType()));
                handler.addHandler(iMatch);
            }
            //注册匹配事件监听器
            listMatchEvent(serviceConfig);
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getCause() + "");
        }
    }

    /**
     * //注册房间回收监听
     */

    private void online(MatchServiceConfig config) {
        final String key = config.getGameID() + UmspConfig.LINK_CHAR_KEY + config.getServiceIndex();
    }

    private void listMatchEvent(final MatchServiceConfig config) {

        EventSubscriber.registerAsyncSubscriberCallBack(new IEventSubscriber() {

            @Override
            public void onMessage(String channel, String message) {
                switch (channel) {
                    case Event.ROOM_SERVICE_ON_LINE:
                        Room.updateRoomServerAddressMap(RoomServiceConfig.fromJson(message));
                        break;
                    default:
                        Match match = Match.fromJson(message, Match.class);
                        match(match, MatchUserManager.INSTANCE);
                        break;
                }
            }

            public void onSubscribe(String s, int i) {
                online(serviceConfig);
            }
        }, getMatchServerIndex(config), Event.ROOM_SERVICE_ON_LINE);
    }

    /**
     * 使用gameID+serviceIndex来计算事件订阅的频道值,实现负载均衡
     *
     * @param config Config
     * @return 服务标识
     */
    public static String getMatchServerIndex(MatchServiceConfig config) {
        return Event.CHANNEL_MATCH_EVENT + UmspConfig.LINK_CHAR_KEY
                + config.getGameID() + UmspConfig.LINK_CHAR_KEY + config.getServiceIndex();
    }

    /**
     * stop service
     */
    public void stop() {
        handler.removeAll();
        final String key = serviceConfig.getGameID() + UmspConfig.LINK_CHAR_KEY + serviceConfig.getServiceIndex();
    }

    private final ExecutorService singleThreadPool = ThreadUtil.createSingleBlockThread(UmspConfig.MAX_TASK_SIZE);

    @Override
    public void match(final Match match, final IMatchedCallBack listener) {
        try {
            singleThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    handler.match(match, listener);
                }
            });
        } catch (RejectedExecutionException e) {
            listener.onMatched(MatchResult.createFailMatchResult(ErrCode.ServiceBusy, match.getWantToMatchUser().userID));
            log.warn("match server is busy!", e);
        }

    }

    @Override
    public int getMatchType() {
        return 0;
    }

    public static void main(String[] args) {
        //启动匹配服务
        MatchService.INSTANCE.start(null);
    }

}
